package com.jpaAutoProcess.kernel;

import com.jpaAutoProcess.utils.ParamConditionBO;
import com.jpaAutoProcess.utils.type.Classtype;
import com.jpaAutoProcess.utils.type.Condition;
import com.jpaAutoProcess.utils.type.PropertyType;
import java.lang.reflect.Field;
import java.math.BigInteger;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * @User c.c
 * @Since V1.0 2022/8/24
 * @Time 10:31
 * @Description 自动分页核心
 */

public class AutoKernel<T> {


  /**
   *v1.3
   *  @author: C.c
   * @date: 2022-08-24 10:40
   * @description: 拼接sql，判断sql条件，放置参数
   **/
  public void spliceSentencesAndPutParams(Map<String,Object> databaseParameters, StringBuilder wheresql, Map<String, Object> params) {

    if (databaseParameters!=null && databaseParameters.size()!=0) {
      wheresql.append(" where 1=1 ");
      databaseParameters.forEach((k,v)->{
        //解析字段和判断条件
        ParamConditionBO fieldAndCondition = ParamConditionBO.parse(k);
        //这个只是放置where参数和组装where语句 一般情况下参数不能为空。若判断条件是，“该字段”非空，“该字段”是空，那么就直接进入
        if (v!=null|| Condition.isNotNull.equals(fieldAndCondition.getCondition())||Condition.isNull.equals(fieldAndCondition.getCondition())){
          putParams(fieldAndCondition,wheresql,params,v);
        }
      });
    }
  }

  /**
   * @author: C.c
   * @date: 2022-08-24 10:40
   * @description: 放置参数 并根据条件 进行不同拼接
   **/
  private void putParams(ParamConditionBO fieldAndCondition,StringBuilder wheresql,Map<String, Object> params,Object v){
    //解析传来v值的数据类型
    PropertyType propertyType = Classtype.judgeClassProperty(v);
    String sqlfield = fieldAndCondition.getPropertyName();
    switch (fieldAndCondition.getCondition()){
      case eq:{
        StringBuilder tempSql = new StringBuilder(" AND ").append(sqlfield).append(" = :").append(sqlfield);
        wheresql.append(tempSql);
        //判断是否出现k值重复
        Object o = params.putIfAbsent(sqlfield, v);
        if (o!=null){
          throw new RuntimeException(new StringBuilder(sqlfield).append(":该属性，这边建议使用in").toString());
        }
        break;
      }
      case like:{
        StringBuilder tempSql = new StringBuilder(" AND ").append(sqlfield).append(" LIKE :").append(sqlfield);
        wheresql.append(tempSql);
        params.put(sqlfield,v);
        break;
      }
      case startwith:{
        StringBuilder tempSql = new StringBuilder(" AND ").append(sqlfield).append(" LIKE :").append(sqlfield);
        wheresql.append(tempSql);
        params.put(sqlfield,v+"%");
        break;
      }
      case endwith:{
        StringBuilder tempSql = new StringBuilder(" AND ").append(sqlfield).append(" LIKE :").append(sqlfield);
        wheresql.append(tempSql);
        params.put(sqlfield,"%"+v);
        break;
      }
      case containing:{
        StringBuilder tempSql = new StringBuilder(" AND ").append(sqlfield).append(" LIKE :").append(sqlfield);
        wheresql.append(tempSql);
        params.put(sqlfield,"%"+v+"%");
        break;
      }

      case between:{
        //进一步进行拼接
        BaseBetweenTypeGeneratedSql(propertyType,v,params,wheresql,sqlfield);
        break;
      }
      case ge:{
        BaseGreaterEqualTypeGeneratedSql(propertyType,v,params,wheresql,sqlfield);
        break;
      }
      case le:{
        BaseLessEqualTypeGeneratedSql(propertyType,v,params,wheresql,sqlfield);
        break;
      }
      case gt:{
        BaseGreatThanTypeGeneratedSql(propertyType,v,params,wheresql,sqlfield);
        break;
      }
      case lt:{
        BaseLessThanTypeGeneratedSql(propertyType,v,params,wheresql,sqlfield);
        break;
      }
      case in:{
        BaseInTypeGeneratedSql(propertyType,v,params,wheresql,sqlfield);
        break;
      }
      case not:{
        StringBuilder tempSql =  new StringBuilder(" AND ").append(sqlfield).append(" <> :").append(sqlfield);
        wheresql.append(tempSql);
        params.put(sqlfield,v);
        break;
      }
      case isNotNull:{
        StringBuilder tempSql = new StringBuilder(" AND ").append(sqlfield).append(" IS NOT NULL");
        wheresql.append(tempSql);
        break;
      }

      case isNull:{
        StringBuilder tempSql = new StringBuilder(" AND ").append(sqlfield).append(" IS NULL");
        wheresql.append(tempSql);
        break;
      }
      default:{
        throw new RuntimeException(new StringBuilder(sqlfield).append("参数：选择了不存在的条件类型").toString());
      }
    }
  }

  /**
   * @author: C.c
   * @date: 2022-08-24 10:40
   * @description: 基于in list数组不同数据，生成不同类型
   **/
  private void BaseInTypeGeneratedSql(PropertyType propertyType, Object v, Map<String, Object> params, StringBuilder wheresql, String sqlfield) {
    if (v instanceof List){
      List list = (List) v;
      //判断数组内的类型
      switch (propertyType){
        case LocalDateTime:{
          //转换成yyyy-MM-dd的String数组
          List<String> timeStrings = new ArrayList<>();
          ((List) v).forEach( param ->{
            DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
            String time = format.format((LocalDateTime) param);
            timeStrings.add(time);
          });
          spliceSentenceOnIn(params, wheresql, sqlfield,timeStrings);
          break;
        }
        case Date:{
          //转换成yyyy-MM-dd的String数组
          List<String> timeStrings = new ArrayList<>();
          ((List) v).forEach( param ->{
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            timeStrings.add(simpleDateFormat.format(param));
          });
          spliceSentenceOnIn(params, wheresql, sqlfield,timeStrings);
          break;
        }
        default:{
          spliceSentenceOnIn(params, wheresql, sqlfield,v);
          break;
        }
      }
    }else {
      throw new RuntimeException("请传递list数组类型");
    }
  }


  /**
   * @author: C.c
   * @date: 2022-08-24 10:40
   * @description: 基于Less than <里不同数据，生成不同类型
   **/
  private void BaseLessThanTypeGeneratedSql(PropertyType propertyType, Object v, Map<String, Object> params, StringBuilder wheresql, String sqlfield) {
    switch (propertyType){
      case LocalDateTime:{
        DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        String time = format.format((LocalDateTime) v);
        spliceSentenceOnlessThan(params,wheresql,sqlfield,time);
        break;
      }
      case Date:{
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String time = simpleDateFormat.format((Date)v);
        spliceSentenceOnlessThan(params,wheresql,sqlfield,time);
        break;
      }
      default:{
        spliceSentenceOnlessThan(params,wheresql,sqlfield,v);
      }
    }
  }

  /**
   * @author: C.c
   * @date: 2022-08-24 10:40
   * @description: 基于great than >里不同数据，生成不同类型
   **/
  private void BaseGreatThanTypeGeneratedSql(PropertyType propertyType, Object v, Map<String, Object> params, StringBuilder wheresql, String sqlfield) {
    switch (propertyType){
      case LocalDateTime:{
        DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        String time = format.format((LocalDateTime) v);
        spliceSentenceOnGreatThan(params,wheresql,sqlfield,time);
        break;
      }
      case Date:{
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String time = simpleDateFormat.format((Date)v);
        spliceSentenceOnGreatThan(params,wheresql,sqlfield,time);
        break;
      }
      default:{
        spliceSentenceOnGreatThan(params,wheresql,sqlfield,v);
        break;
      }
    }
  }


  /**
   * @author: C.c
   * @date: 2022-08-24 10:40
   * @description: 基于Less equal <=里不同数据，生成不同类型
   **/
  private void BaseLessEqualTypeGeneratedSql(PropertyType propertyType, Object v, Map<String, Object> params, StringBuilder wheresql, String sqlfield) {
    switch (propertyType){
      case LocalDateTime:{
        DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        String time = format.format((LocalDateTime) v);
        spliceSentenceOnLessEqual(params,wheresql,sqlfield,time);
        break;
      }
      case Date:{
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String time = simpleDateFormat.format((Date)v);
        spliceSentenceOnLessEqual(params,wheresql,sqlfield,time);
        break;
      }
      default:{
        spliceSentenceOnLessEqual(params,wheresql,sqlfield,v);
        break;
      }
    }
  }



  /**
   * @author: C.c
   * @date: 2022-08-24 10:40
   * @description: 基于greater equal >=里不同数据，生成不同类型
   **/
  private void BaseGreaterEqualTypeGeneratedSql(PropertyType propertyType, Object v, Map<String, Object> params, StringBuilder wheresql, String sqlfield) {
    switch (propertyType){
      case LocalDateTime:{
        DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        String time = format.format((LocalDateTime) v);
        spliceSentenceOnGreaterEqual(params,wheresql,sqlfield,time);
        break;
      }
      case Date:{
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String time = simpleDateFormat.format((Date)v);
        spliceSentenceOnGreaterEqual(params,wheresql,sqlfield,time);
        break;
      }
      default:{
        spliceSentenceOnGreaterEqual(params,wheresql,sqlfield,v);
        break;
      }
    }
  }


  /**
   * @author: C.c
   * @date: 2022-08-24 10:40
   * @description: 基于between里不同数据，生成不同类型
   **/
  private void BaseBetweenTypeGeneratedSql(PropertyType propertyType, Object v, Map<String, Object> params, StringBuilder wheresql, String sqlfield) {
    //判断v是否是list
    if (v instanceof List) {
      if (((List) v).size()!=2){
        throw new RuntimeException("between条件应为两条");
      }
      switch (propertyType) {
        case LocalDateTime: {
          //把数组取出来
          LocalDateTime param1 = (LocalDateTime) ((List) v).get(0);
          LocalDateTime param2 = (LocalDateTime) ((List) v).get(1);
          DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
          String starttime = format.format(param1);
          String endtime = format.format(param2);

          spliceSentenceOnBetween(params, wheresql, sqlfield, starttime, endtime);

          break;
        }

        case Date:{
          Date param1 = (Date) ((List) v).get(0);
          Date param2 = (Date) ((List) v).get(1);
          SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
          String starttime = simpleDateFormat.format(param1);
          String endtime = simpleDateFormat.format(param2);
          spliceSentenceOnBetween(params, wheresql, sqlfield, starttime, endtime);
          break;
        }
        case Integer:{
          Integer num1 = (Integer) ((List) v).get(0);
          Integer num2 = (Integer) ((List) v).get(1);
          spliceSentenceOnBetween(params,wheresql,sqlfield,num1,num2);
          break;
        }
        case Long:{
          Long long1 = (Long) ((List) v).get(0);
          Long long2 = (Long) ((List) v).get(1);
          spliceSentenceOnBetween(params,wheresql,sqlfield,long1,long2);
          break;
        }
        case BigDecimal:{
          BigInteger bigInteger1 = (BigInteger) ((List) v).get(0);
          BigInteger bigInteger2 = (BigInteger) ((List) v).get(1);
          spliceSentenceOnBetween(params,wheresql,sqlfield,bigInteger1,bigInteger2);
          break;
        }
        case String:{
          String string1 = (String) ((List) v).get(0);
          String string2 = (String) ((List) v).get(1);
          spliceSentenceOnBetween(params,wheresql,sqlfield,string1,string2);
          break;
        }
        default:{
          Object o1 = ((List) v).get(0);
          Object o2 = ((List) v).get(1);
          spliceSentenceOnBetween(params,wheresql,sqlfield,o1,o2);
          break;
        }
      }
    }
  }


  /**
   * @author: C.c
   * @date: 2022-08-24 10:40
   * @description: between条件拼接 根據參數 动态拼接<= 和 >=
   **/
  private void spliceSentenceOnBetween(Map<String, Object> params, StringBuilder wheresql, String sqlfield, Object param1, Object param2) {
    StringBuilder sql1 = new StringBuilder(" AND ").append(sqlfield).append(" >= :").append(sqlfield);
    params.put(sqlfield, param1);

    //因为map k值唯一，所以需要做特殊处理
    StringBuilder sqlfield2 = new StringBuilder(sqlfield).append("1");
    StringBuilder sql2 = new StringBuilder(" AND ").append(sqlfield).append(" <= :").append(sqlfield2);
    params.put(sqlfield2.toString(), param2);

    wheresql.append(sql1).append(sql2);
  }


  /**
   * @author: C.c
   * @date: 2022-08-24 10:40
   * @description: greater equal条件拼接 根據參數 动态拼接>=
   **/
  private void spliceSentenceOnGreaterEqual(Map<String, Object> params, StringBuilder wheresql, String sqlfield, Object param) {
    String onlyValue = new StringBuilder(sqlfield).append(param.hashCode()).toString();
    StringBuilder sql = new StringBuilder(" And ").append(sqlfield).append(" >= :").append(onlyValue);
    params.put(onlyValue,param);
    wheresql.append(sql);
  }

  /**
   * @author: C.c
   * @date: 2022-08-24 10:40
   * @description: less equal条件拼接 根據參數 动态拼接<=
   **/
  private void spliceSentenceOnLessEqual(Map<String, Object> params, StringBuilder wheresql, String sqlfield, Object param) {
    String onlyValue = new StringBuilder(sqlfield).append(param.hashCode()).toString();
    StringBuilder sql = new StringBuilder(" And ").append(sqlfield).append(" <= :").append(onlyValue);
    params.put(onlyValue,param);
    wheresql.append(sql);
  }


  /**
   * @author: C.c
   * @date: 2022-08-24 10:40
   * @description: grate than条件拼接 根據參數 动态拼接 >
   **/
  private void spliceSentenceOnGreatThan(Map<String, Object> params, StringBuilder wheresql, String sqlfield, Object param) {
    String onlyValue = new StringBuilder(sqlfield).append(param.hashCode()).toString();
    StringBuilder sql = new StringBuilder(" And ").append(sqlfield).append(" > :").append(onlyValue);
    params.put(onlyValue,param);
    wheresql.append(sql);
  }

  /**
   * @author: C.c
   * @date: 2022-08-24 10:40
   * @description: less than条件拼接 根據參數 动态拼接 <
   **/
  private void spliceSentenceOnlessThan(Map<String, Object> params, StringBuilder wheresql, String sqlfield, Object param) {
    String onlyValue = new StringBuilder(sqlfield).append(param.hashCode()).toString();
    StringBuilder sql = new StringBuilder(" And ").append(sqlfield).append(" < :").append(onlyValue);
    params.put(onlyValue,param);
    wheresql.append(sql);
  }

  /**
   * @author: C.c
   * @date: 2022-08-24 10:40
   * @description: in条件拼接 根據參數 动态拼接 in
   **/
  private void spliceSentenceOnIn(Map<String, Object> params, StringBuilder wheresql, String sqlfield, Object param) {
    StringBuilder sql = new StringBuilder(" And ").append(sqlfield).append(" in :").append(sqlfield);
    params.put(sqlfield,param);
    wheresql.append(sql);
  }

  private Object reflectObject(String paramname,Object o)  {
    Class<?> aClass = o.getClass();
    Field[] declaredFields = aClass.getDeclaredFields();
    String property = paramname.toLowerCase();
    //取具体值
    for (Field declaredField : declaredFields) {
      if (declaredField.getName().contains(property)){
        declaredField.setAccessible(true);
        Object result = null;
        try {
          result = declaredField.get(o);
        } catch (IllegalAccessException e) {
          e.printStackTrace();
        }
        return result;
      }
    }
    return null;
  }

}
